/**
 * @file BMPImage.h
 * @author SDK_TEAM
 * @brief
 * @version 0.1
 * @date 2022-11-09
 *
 * Copyright:
 * © 2018 北京灵汐科技有限公司 版权所有。
 * 注意：以下内容均为北京灵汐科技有限公司原创，未经本公司允许，不得转载，否则将视为侵权；对于不遵守此声明或者其他违法使用以下内容者，本公司依法保留追究权。
 * © 2018 Lynxi Technologies Co., Ltd. All rights reserved.
 * NOTICE: All information contained here is, and remains the property of Lynxi.
 * This file can not be copied or distributed without the permission of Lynxi
 * Technologies Co., Ltd.
 *
 */

#pragma once
#include <string.h>
#include <iostream>
#include <string>

/********************************************************************************
Description: 将图像数据保存为BMP文件
*******************************************************************************/

#pragma pack(2)

/**
 * @brief BMP文件头
 */
typedef struct {
  unsigned short type;       // 2 字节 文件类型 值为0x4D42
  unsigned int size;         // 4 字节 文件大小
  unsigned short reserved1;  // 2 字节 保留字段
  unsigned short reserved2;  // 2 字节 保留字段
  unsigned int offset;  // 4 字节 文件头到实际图像数据之间的字节偏移量
} BMPFileHeader;  // 共14个字节

/**
 * @brief BMP信息头
 */
typedef struct {
  unsigned int size;         // 4 字节 信息头的大小 40
  int width;                 // 4 字节 图像宽 单位是像素
  int height;                // 4 字节 图像高 单位是像素
  unsigned short planes;     // 2 字节 平面属性
  unsigned short bitCount;   // 2 字节 比特数/像素
  unsigned int compression;  // 4 字节 压缩类型 0 不压缩
  unsigned int sizeImage;    // 4 字节 图像的大小
  int XPelsPerMeters;        // 4 字节 水平分辨率
  int YPelsPerMeters;        // 4 字节 垂直分辨率
  unsigned int
      clrUsed;  // 4 字节 位图使用的彩色表中的颜色索引数 为0则使用所有调色板项
  unsigned int
      clrImoprtant;  // 4 字节 对图像演示有重要影响的研所所有的数目，为0则都重要
} BMPInfoHeader;     // 共40个字节
#pragma pack(8)

/**
 * @brief transform pic from BGR to BMP
 *
 * @param[in]  bmpName pic name
 * @param[in]  imgBuf  a pointer of pic data
 * @param[in]  width   pic width
 * @param[in]  height  pic height
 *
 * @return 成功返回0, 否则返回-1
 */
int SaveBmp(const std::string bmpName, char *imgBuf, int width, int height) {
  if (!imgBuf) {
    return -1;
  }

  const unsigned short bitCount = 24;  // BGR图像每像素占的位数
  const unsigned short bit = 8;        // 每个字节的比特数

  // 要求每行字节数为4的倍数
  int lineByte = (width * bitCount / bit + 3) / 4 * 4;

  BMPFileHeader fileHead;
  fileHead.type = 0x4D42;  // 说明bmp文件类型
  fileHead.size =
      sizeof(BMPFileHeader) + sizeof(BMPInfoHeader) + lineByte * height;
  fileHead.reserved1 = 0;
  fileHead.reserved2 = 0;
  fileHead.offset = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader);

  // 写文件头
  FILE *fp = fopen(bmpName.data(), "wb");
  if (fp == 0) {
    return -1;
  }
  fwrite(&fileHead, sizeof(BMPFileHeader), 1, fp);

  BMPInfoHeader infoHeader;
  infoHeader.bitCount = bitCount;  // BGR图像每像素占的位数
  infoHeader.clrImoprtant = 0;
  infoHeader.clrUsed = 0;
  infoHeader.compression = 0;
  infoHeader.planes = 1;
  infoHeader.width = width;
  infoHeader.height = -height;  // 图像是正向的
  infoHeader.size = sizeof(BMPInfoHeader);
  infoHeader.sizeImage = lineByte * height;
  infoHeader.XPelsPerMeters = 0;
  infoHeader.YPelsPerMeters = 0;

  fwrite(&infoHeader, sizeof(BMPInfoHeader), 1, fp);

  // 处理行像素非被4整除的情况，补零
  if (((width * bitCount / bit) % 4) != 0) {
    char *buf = new char[(lineByte - width * 3)];
    memset(buf, 0, (lineByte - width * 3));
    for (int i = 0; i < height; i++) {
      fwrite(imgBuf, width * 3, 1, fp);
      fwrite(buf, (lineByte - width * 3), 1, fp);
      imgBuf = imgBuf + width * 3;
    }
    delete[] buf;
  } else {
    fwrite(imgBuf, height * lineByte, 1, fp);
  }

  fclose(fp);
  return 0;
}